package com.zh.work.service.jy.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zh.work.service.jy.JyService;
import com.zh.work.util.jy.*;
import com.zh.work.util.plateform.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.HandlerInterceptor;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * code is far away from bug with the animal protecting
 * ┏┓　　　┏┓
 * ┏┛┻━━━┛┻┓
 * ┃　　　　　　　┃
 * ┃　　　━　　　┃
 * ┃　┳┛　┗┳　┃
 * ┃　　　　　　　┃
 * ┃　　　┻　　　┃
 * ┃　　　　　　　┃
 * ┗━┓　　　┏━┛
 * 　　┃　　　┃神兽保佑
 * 　　┃　　　┃代码无BUG！
 * 　　┃　　　┗━━━┓
 * 　　┃　　　　　　　┣┓
 * 　　┃　　　　　　　┏┛
 * 　　┗┓┓┏━┳┓┏┛
 * 　　　┃┫┫　┃┫┫
 * 　　　┗┻┛　┗┻┛
 *
 * @Description: 骏聿业务接口实现
 * @Author: Liard
 * @Create in: 2020/6/27 9:41
 * @Version: 1.0.1
 */
@Service
@Slf4j
public class JyServiceImpl implements JyService {


    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private MsgNotify notify;

    @Autowired
    private RedisTemplate redisTemplate;
    private Integer i = 1;


    @Override
    public JSONObject comPare(Map<String, String> map) throws Exception {
        JSONObject jsonObject = new JSONObject();
        // 系统时间
        String strTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String sName = map.get("sName");
//        String sName = "李辉能";
        String sId = map.get("sId");
        // 校验验证次数
        redisValid(sName, sId, "comPare");
//        String sId = "421121199706027019";
        // 发起证书申请用户主体信息签名
        String pact_sign = JYMD5.MD5Encoder(sName + sId);
        // 姓名
        String name = AesUtil.encrypt(sName, JY_ENUM.I_APP_SECRET.getValue());
        // 身份证号码
        String id = AesUtil.encrypt(sId, JY_ENUM.I_APP_SECRET.getValue());
        // 身份证照片
//        String id_photo = JYMD5.encrypt(Base64ImgUtil.GetImageStr("http://120.79.142.28:8888/group1/M00/00/11/rBAVtl8f_7-AapphAAFhwHZ5YrA724.jpg"));
        String id_photo = JYMD5.encrypt(Base64ImgUtil.GetImageStr(map.get("sPhoto")));
        // 活体数据包
        String data_photo = map.get("sGh");
        // 防止翻拍照片  0关闭，1开启
        String strhacker = "1";
        JSONObject param = new JSONObject();
        // 姓名
        param.put("name", name);
        // 身份证号
        param.put("id_card", id);
        param.put("data_photo", data_photo);
        param.put("id_photo", id_photo);
        param.put("anti_hacker", strhacker);
        JSONObject par = new JSONObject();
        par.put("biz_content", param);
        par.put("license_code", JY_ENUM.I_LICENSE.getValue());
        // 业务流水号
        par.put("sys_req_sn", strTime);
        par.put("timestamp", strTime);
        par.put("pact_trade_no", JY_ENUM.PACT_TRADE_NO.getValue());
        par.put("pact_sign", pact_sign);
        par.put("scene_code", JY_ENUM.I_SCENE_CODE.getValue());
        par.put("save_cer", strTime);
        par.put("pact_no", JY_ENUM.PACT_NO.getValue());
        String sign = JYMD5.createSignature(par, JY_ENUM.I_APP_SECRET.getValue());
        par.put("sign", sign);
        par.put("biz_content", param);
        String result = null;
        TimeInterval timer = DateUtil.timer();
        try {
            result = ClientUtil.post(JY_ENUM.I_URL.getValue(), par.toString());
        } catch (Exception e) {
            log.error("网络连接超时!");
            map.put("errorMsg", "网络超时");
        }
        map.put("timed", String.valueOf(timer.interval()));
//        String result = "false";
        log.info("骏聿【 I 】类A型认证结果：{}", result);
        map.put("_id", UUID.randomUUID().toString());
        map.put("method", "comPare");
        map.put("timestamp", strTime);
        map.put("result", result);
        map.remove("sGh");
        //解密详情信息
        jsonObject = JSON.parseObject(result);
        map.put("flag", jsonObject.getJSONObject("jy_response").getString("code"));
        mongoTemplate.save(map, "jy_api");
        if (Objects.nonNull(result)) {
            if (jsonObject.getJSONObject("jy_response").getString("code").equals("0")) {
                jsonObject.put("success", true);
                jsonObject.put("message", "认证成功!");
                jsonObject.put("code", "100");
                notify.msgNotify(String.valueOf(map.get("uId")), "1", "1");
            } else {
                if (i == 0) {
                    jsonObject.put("code", "202");
                    jsonObject.put("success", false);
                    jsonObject.put("message", "认证次数超过限制,请上传照片进行认证!");
                    notify.msgNotify(String.valueOf(map.get("uId")), "1", "4");
                    return jsonObject;
                } else {
                    jsonObject.put("success", false);
                    jsonObject.put("code", "204");
                }
                String code = jsonObject.getJSONObject("jy_response").getString("sub_code");
                String s = "";
                s = "您当前认证剩余次数为：" + i;
                if (code.equals("-1010"))
                    jsonObject.put("message", "请检查身份证照明与法人是否为同一主体." + s);
                else if (code.equals("-1011"))
                    jsonObject.put("message", "请确认姓名或身份证号码是否录入有误." + s);
                else if (code.equals("-1012"))
                    jsonObject.put("message", "请传输正确的法人身份证照片." + s);
                else if (code.equals("-1013"))
                    jsonObject.put("message", "面部特征提取失败，请重新采集照片." + s);
                else if (code.equals("-1014"))
                    jsonObject.put("message", "认证失败,提取多个面部照片." + s);
                else if (code.equals("-1044") || code.equals("-1045") || code.equals("-1046") || code.equals("-1047"))
                    jsonObject.put("message", "无法抓取面部特征,请确保周边光线充足." + s);
                else if (code.equals("-3001") || code.equals("-3002"))
                    jsonObject.put("message", "请确保识别主体与提交资料保持一致性." + s);
                else
                    jsonObject.put("message", jsonObject.getJSONObject("jy_response").getString("sub_msg") + s);
            }
        } else {
            jsonObject.put("success", false);
            jsonObject.put("code", "204");
            jsonObject.put("message", "网络超时，请稍后重试");
        }
        return jsonObject;
    }

    @Override
    public JSONObject doCheck(Map<String, String> map) throws Exception {
        JSONObject jsonObject = new JSONObject();
        String strTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String sName = map.get("sName");
        String sId = map.get("sId");
        redisValid(sName, sId, "doCheck");
        // 身份证号码验证
        if (!IdcardUtil.isValidCard(sId)) {
            jsonObject.put("success", false);
            jsonObject.put("message", "请输入正确的身份证号码!");
            jsonObject.put("code", "204");
            return jsonObject;
        }
        String pact_sign = JYMD5.MD5Encoder(sName + sId);
        //主体参数：姓名
        String name = AesUtil.encrypt(sName, JY_ENUM.II_APP_SECRET.getValue());
        //主体参数：身份证号码
        String id = AesUtil.encrypt(sId, JY_ENUM.II_APP_SECRET.getValue());
        // 信用卡类型验证和正确号码验证
        String result1 = HttpUtil.get("https://ccdcapi.alipay.com/validateAndCacheCardInfo.json?_input_charset=utf-8&cardBinCheck=true&cardNo=" + map.get("sBankCard"));
        Map cardMap = JSON.parseObject(result1, Map.class);
        if (!CardUtil.cardValid(map.get("sBankCard"))) {
            jsonObject.put("success", false);
            jsonObject.put("message", "请输入正确的信用卡号!");
            jsonObject.put("code", "204");
            return jsonObject;
        } else if (!(Boolean) cardMap.get("validated")) {
            jsonObject.put("success", false);
            jsonObject.put("message", "认证失败，请输入正确的信用卡卡号!");
            jsonObject.put("code", "204");
            return jsonObject;
        } else if (!cardMap.get("cardType").equals("CC")) {
            jsonObject.put("success", false);
            jsonObject.put("message", "请检查输入是否为信用卡卡号!");
            jsonObject.put("code", "204");
            return jsonObject;
        }
        // 主体参数：银行卡号
        String bank_card = AesUtil.encrypt(map.get("sBankCard"), JY_ENUM.II_APP_SECRET.getValue());
        // 手机号正则
        String pattern = "^(?:\\+?86)?1(?:3\\d{3}|5[^4\\D]\\d{2}|8\\d{3}|7(?:[0-35-9]\\d{2}|4(?:0\\d|1[0-2]|9\\d))|9[0-35-9]\\d{2}|6[2567]\\d{2}|4(?:(?:10|4[01])\\d{3}|[68]\\d{4}|[579]\\d{2}))\\d{6}$";
        boolean b = Pattern.matches(pattern, map.get("sMobile"));
        if (!b) {
            jsonObject.put("success", false);
            jsonObject.put("message", "请输入正确的手机号!");
            jsonObject.put("code", "204");
            return jsonObject;
        }
        //预留手机号
        String mobile = AesUtil.encrypt(map.get("sMobile"), JY_ENUM.II_APP_SECRET.getValue());
        //证件类型，默认“0”身份证，具体类型列表请见接口文档，当前仅支持身份证证件类型。
        String identity_type = "0";
        JSONObject param = new JSONObject();
        param.put("name", name);
        param.put("id_card", id);
        param.put("bank_card", bank_card);
        param.put("mobile", mobile);
        param.put("identity_type", identity_type);
        JSONObject par = new JSONObject();
        par.put("biz_content", param);
        par.put("license_code", JY_ENUM.II_LICENSE.getValue());
        par.put("sys_req_sn", strTime);
        par.put("timestamp", strTime);
        par.put("pact_trade_no", JY_ENUM.PACT_TRADE_NO.getValue());
        par.put("pact_sign", pact_sign);
        par.put("scene_code", JY_ENUM.II_SCENE_CODE.getValue());
        par.put("save_cer", strTime);
        par.put("pact_no", JY_ENUM.PACT_NO.getValue());
        //信息防篡改签名
        String sign = JYMD5.createSignature(par, JY_ENUM.II_APP_SECRET.getValue());
        par.put("sign", sign);
        par.put("biz_content", param);
        TimeInterval timer = DateUtil.timer();
        String result = null;
        try {
            result = ClientUtil.post(JY_ENUM.II_URL.getValue(), par.toString());
        } catch (Exception e) {
            log.error("网络连接超时!");
            map.put("errorMsg", "网络超时");
        }
        map.put("timed", String.valueOf(timer.interval()));
        log.info("骏聿【 II 】类A型认证结果：{}", result);
        map.put("_id", UUID.randomUUID().toString());
        map.put("method", "doCheck");
        map.put("timestamp", strTime);
        map.put("result", result);
        map.remove("sPhoto");
        jsonObject = JSON.parseObject(result, JSONObject.class);
        map.put("flag", jsonObject.getJSONObject("jy_response").getString("code"));
        mongoTemplate.save(map, "jy_api");
        if (Objects.nonNull(result)) {
            if (jsonObject.getJSONObject("jy_response").getString("code").equals("0")) {
                jsonObject.put("success", true);
                jsonObject.put("message", "认证成功!");
                jsonObject.put("code", "100");
                notify.msgNotify(String.valueOf(map.get("uId")), "2", "1");
            } else {
                if (i == 0) {
                    jsonObject.put("code", "202");
                    jsonObject.put("success", false);
                    jsonObject.put("message", "认证次数超过限制,请上传照片进行认证!");
                    notify.msgNotify(String.valueOf(map.get("uId")), "2", "4");
                    return jsonObject;
                } else {
                    jsonObject.put("success", false);
                    jsonObject.put("code", "204");
                }
                String s = "";
                s = "您当前认证剩余次数为：" + i;
                if (jsonObject.getJSONObject("jy_response").getString("sub_code").equals("-1031")) {
                    jsonObject.put("message", "认证失败,请确认是否为法人资料提交." + s);
                } else if (jsonObject.getJSONObject("jy_response").getString("sub_code").equals("-2008")) {
                    jsonObject.put("message", "认证失败,请输入正确的银行卡号." + s);
                } else if (jsonObject.getJSONObject("jy_response").getString("sub_code").equals("-3002")) {
                    jsonObject.put("message", "认证失败,请输入正确的身份证号码." + s);
                } else {
                    jsonObject.put("message", jsonObject.getJSONObject("jy_response").getString("sub_msg") + s);
                }
            }
        } else {
            jsonObject.put("success", false);
            jsonObject.put("code", "204");
            jsonObject.put("message", "网络超时，请稍后重试");
        }
        return jsonObject;
    }

    @Override
    public JSONObject bankCard(Map<String, String> map) throws Exception {
        String strTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        //照片转base64后替换字符加密
        String photo = JYMD5.encrypt(Base64ImgUtil.GetImageStr(map.get("BANK_CARD")));
        JSONObject param = new JSONObject();
        param.put("photo", photo);
        JSONObject par = new JSONObject();
        par.put("biz_content", param);
        par.put("license_code", JY_ENUM.BANK_LICENSE.getValue());
        par.put("scene_code", JY_ENUM.BANK_SCENE_CODE.getValue());
        par.put("pact_no", JY_ENUM.PACT_NO.getValue());
        par.put("pact_trade_no", JY_ENUM.PACT_TRADE_NO.getValue());
        par.put("pact_sign", JY_ENUM.PACT_SIGN.getValue());
        par.put("sys_req_sn", strTime);
        par.put("timestamp", strTime);
        String sign = JYMD5.createSignature(par, JY_ENUM.BANK_APP_SECRET.getValue());
        par.put("sign", sign);
        par.put("biz_content", param);
        String result = ClientUtil.post(JY_ENUM.BANK_URL.getValue(), par.toString());
        log.info("骏聿 银行卡认证结果：{}", result);
        map.put("_id", UUID.randomUUID().toString());
        map.put("method", "bankCard");
        map.put("timestamp", strTime);
        map.put("result", result);
        map.put("logNo", par.toString());
        mongoTemplate.save(map, "jy_api");
        //解密详情信息
        JSONObject jsonObject = JSON.parseObject(result);
        if (jsonObject.getJSONObject("jy_response").getString("code").equals("0")) {
            String data_info = jsonObject.getJSONObject("jy_response").getString("data");
            JSONObject info = JSON.parseObject(data_info);
            String card_number = AesUtil.decrypt(info.get("card_number").toString(), JY_ENUM.BANK_APP_SECRET.getValue());
            log.info("骏聿 卡号---> {}", card_number);
            jsonObject.put("success", true);
            jsonObject.put("message", "成功!");
            jsonObject.put("data", card_number);
        } else {
            jsonObject.put("success", false);
            jsonObject.put("message", jsonObject.getJSONObject("jy_response").getString("sub_msg"));
        }
        return jsonObject;
    }

    @Override
    public JSONObject idData(Map<String, String> map) throws Exception {
        String strTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());//时间
        String photo = JYMD5.encrypt(Base64ImgUtil.GetImageStr(map.get("ID_CARD")));//身份证照片
        String card_type = "0";//0为 人像面  1为国徽面
        String head_option = "1";//是否返回头像开关 0 关闭 1打开
        JSONObject param = new JSONObject();
        param.put("card_type", card_type);
        param.put("head_option", head_option);
        param.put("photo", photo);

        JSONObject par = new JSONObject();
        par.put("biz_content", param);
        par.put("license_code", JY_ENUM.ID_LICENSE.getValue());
        par.put("scene_code", JY_ENUM.ID_SCENE_CODE.getValue());
        par.put("pact_no", JY_ENUM.PACT_NO.getValue());
        par.put("pact_trade_no", JY_ENUM.PACT_TRADE_NO.getValue());
        par.put("pact_sign", JY_ENUM.PACT_SIGN.getValue());

        par.put("sys_req_sn", strTime);
        par.put("timestamp", strTime);
        String sign = JYMD5.createSignature(par, JY_ENUM.ID_APP_SECRET.getValue());
        par.put("sign", sign);
        par.put("biz_content", param);
        String result = ClientUtil.post(JY_ENUM.ID_URL.getValue(), par.toString());
        log.info("骏聿 身份证认证结果：{}", result);
        map.put("_id", UUID.randomUUID().toString());
        map.put("method", "idData");
        map.put("timestamp", strTime);
        map.put("result", result);
        map.put("logNo", par.toString());
        mongoTemplate.save(map, "jy_api");
        //解密详情信息
        JSONObject jsonObject = JSON.parseObject(result);
        if (JsonUtil.getColumns(jsonObject.toString(), "jy_response.code").equals("0")) {
            String data_info = jsonObject.getJSONObject("jy_response").getString("data");
            JSONObject info = JSON.parseObject(data_info);
            String head_photo = JYMD5.decrypt(info.get("head_photo").toString());
            String name = AesUtil.decrypt(info.get("name").toString(), JY_ENUM.ID_APP_SECRET.getValue());
            String certid = AesUtil.decrypt(info.get("certid").toString(), JY_ENUM.ID_APP_SECRET.getValue());
            String address = AesUtil.decrypt(info.get("address").toString(), JY_ENUM.ID_APP_SECRET.getValue());
            log.info("头--->" + head_photo);
            log.info("名--->" + name);
            log.info("号--->" + certid);
            log.info("址--->" + address);
            jsonObject.put("success", true);
            jsonObject.put("message", "成功");
        } else {
            jsonObject.put("success", false);
            jsonObject.put("message", jsonObject.get("sub_msg"));

        }
        return jsonObject;
    }

    private int redisValid(String sName, String sId, String sMethod) {
        boolean b = redisTemplate.hasKey(sName + sId + sMethod);
        // 第一次进入，设置一个初始值，并记录次数
        if (!b) {
            i = 1;
            if (sMethod.equals("comPare")) {
                redisTemplate.opsForValue().set(sName + sId + sMethod, i, 365, TimeUnit.DAYS);
            } else {
                redisTemplate.opsForValue().set(sName + sId + sMethod, i, 1, TimeUnit.DAYS);
            }
            return 1;
        } else {
            i = (Integer) redisTemplate.opsForValue().get(sName + sId + sMethod);
            if (i > 0) {
                i--;
                if (sMethod.equals("comPare")) {
                    redisTemplate.opsForValue().set(sName + sId + sMethod, i, 365, TimeUnit.DAYS);
                } else {
                    redisTemplate.opsForValue().set(sName + sId + sMethod, i, 1, TimeUnit.DAYS);
                }
                log.info("{} ==> {}认证剩余次数：{}", sMethod, sName, i);
                return i;
            } else {
                return -1;
            }
        }
    }


}
